package common

import (
	"fmt"
	"strconv"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

const (
	WorkersNum int = 5
)

var GlobalPool *WorkerPool

func init() {
	GlobalPool = NewWorkerPool(WorkersNum)
}

var times int

type FinalData struct {
	Data []InnerData
}

type InnerData struct {
	Id  int
	Ids []int
}

type WorkerFuncArgs struct {
	SubFuncWg *sync.WaitGroup
	StopChan  chan error

	UrlDataIds []string

	// 增量数据
	IncrementFlag  bool
	AfterTimeStamp *bool
	TimeStamp      time.Time

	times *int
	// 最终数据
	FinalData *FinalData
	// 最终数据中的下标
	// 范围左闭右开 [StartIndex,EndIndex)
	StartIndex *int
	EndIndex   *int
	// 最终数据中的下标
	FinalDataIndex int
	// 填入Url中的DataId
	DataId string
}

var cnt atomic.Int32

type WorkerTask struct {
	Father     bool
	Args       WorkerFuncArgs
	FatherFunc func(args *WorkerFuncArgs) (bool, error)
	SubFunc    func(args *WorkerFuncArgs) error
}

type WorkerPool struct {
	workers   chan *Worker
	taskQueue chan *WorkerTask
}

type Worker struct {
	id        int
	pool      *WorkerPool
	taskQueue chan *WorkerTask
}

func NewWorker(id int, pool *WorkerPool) *Worker {
	return &Worker{
		id:        id,
		pool:      pool,
		taskQueue: make(chan *WorkerTask),
	}
}

func (w *Worker) Start() {
	go func() {
		for task := range w.taskQueue {
			funcArgs := task.Args
			if task.Father {
				fmt.Println("执行father的WorkerId:", w.id)
				hasNext, err := task.FatherFunc(&funcArgs)
				if !hasNext || err != nil {
					funcArgs.StopChan <- err
					continue
				}
				*funcArgs.times += 1
				nextPageTask := &WorkerTask{
					Father:     true,
					Args:       funcArgs,
					FatherFunc: task.FatherFunc,
					SubFunc:    task.SubFunc,
				}
				// 1、先将下一个页面的请求放入workerTasks
				w.pool.Submit(nextPageTask)

				msg := "startIndex:" + strconv.Itoa(*funcArgs.StartIndex) + " end:" + strconv.Itoa(*funcArgs.EndIndex)
				fmt.Println(msg)
				// 2、将获取的数据取出后，将每一条插入workerTasks中
				startIndex := *funcArgs.StartIndex
				endIndex := *funcArgs.EndIndex
				UrlDataIdIndex := 0
				for startIndex < endIndex {
					funcArgs.FinalDataIndex = startIndex
					funcArgs.DataId = funcArgs.UrlDataIds[UrlDataIdIndex]
					subTask := &WorkerTask{
						Father:     false,
						Args:       funcArgs,
						FatherFunc: task.FatherFunc,
						SubFunc:    task.SubFunc,
					}
					funcArgs.SubFuncWg.Add(1)
					w.pool.Submit(subTask)
					startIndex += 1
					UrlDataIdIndex += 1
				}
				fmt.Println("总共add的数量:", UrlDataIdIndex)
				//recordArgs.Msg = "一共:" + strconv.Itoa(UrlDataIdIndex) + "全部提交成功"
			} else {
				err := task.SubFunc(&funcArgs)
				//fmt.Println("workerId:", w.id)
				funcArgs.SubFuncWg.Done()
				//recordArgs := RecordArgs{
				//	Log:      funcArgs.Log,
				//	TaskName: TaskNameMergeRequest,
				//	Err:      nil,
				//	Export:   true,
				//}
				//recordArgs.Msg = "获取评论" + funcArgs.DataId
				//recordTask(recordArgs)
				if err != nil {
					funcArgs.StopChan <- err
					continue
				}
			}

			w.pool.workers <- w
		}
	}()
}

func (w *Worker) Stop() {
	close(w.taskQueue)
}

func NewWorkerPool(numWorkers int) *WorkerPool {
	pool := &WorkerPool{
		workers:   make(chan *Worker, numWorkers),
		taskQueue: make(chan *WorkerTask),
	}

	for i := 0; i < numWorkers; i++ {
		worker := NewWorker(i, pool)
		//pool.workers[i] = worker
		pool.workers <- worker
		worker.Start()
	}

	go pool.processTasks()

	return pool
}

func (p *WorkerPool) processTasks() {
	for task := range p.taskQueue {
		worker := p.getNextWorker()
		worker.taskQueue <- task
	}
}

func (p *WorkerPool) getNextWorker() *Worker {
	return <-p.workers
}

func (p *WorkerPool) Submit(task *WorkerTask) {
	p.taskQueue <- task
}

func childWorkerFunc(args *WorkerFuncArgs) error {
	args.FinalData.Data[args.FinalDataIndex].Ids = append(args.FinalData.Data[args.FinalDataIndex].Ids, args.FinalData.Data[args.FinalDataIndex].Id)
	args.FinalData.Data[args.FinalDataIndex].Ids = append(args.FinalData.Data[args.FinalDataIndex].Ids, args.FinalData.Data[args.FinalDataIndex].Id)
	args.FinalData.Data[args.FinalDataIndex].Ids = append(args.FinalData.Data[args.FinalDataIndex].Ids, args.FinalData.Data[args.FinalDataIndex].Id)
	return nil
}

func fatherWorkerFunc(args *WorkerFuncArgs) (bool, error) {
	var data []InnerData
	var UrlDataIds []string
	afterTimeStamp := false
	if *args.times <= 1 {
		data = make([]InnerData, 100)
		afterTimeStamp = true
	} else if *args.times <= 2 {
		data = make([]InnerData, 90)
	} else {
		data = make([]InnerData, 0)
	}
	for idx := range data {
		data[idx] = InnerData{
			Id:  idx + *args.times*100,
			Ids: nil,
		}
		UrlDataIds = append(UrlDataIds, strconv.Itoa(idx+*args.times*100))
	}

	// 第一次会放过，后续就会阻塞住等待任务完成
	if args.SubFuncWg != nil {
		fmt.Println("我将在这里等住", args.FinalData)
		args.SubFuncWg.Wait()
		if args.IncrementFlag &&
			!*args.AfterTimeStamp {
			return false, nil
		}
	}
	if len(data) == 0 {
		return false, nil
	}

	*args.AfterTimeStamp = afterTimeStamp
	args.SubFuncWg = &sync.WaitGroup{}
	*args.StartIndex = *args.EndIndex
	*args.EndIndex = *args.StartIndex + len(data)
	args.UrlDataIds = UrlDataIds

	args.FinalData.Data = append(args.FinalData.Data, data...)

	return true, nil
}

func TestRun(t *testing.T) {
	var data FinalData
	stopChan := make(chan error)
	afterTimeStamp := false

	times = 0
	startIndex := 0
	endIndex := 0

	workerFuncArgs := WorkerFuncArgs{
		SubFuncWg:      nil,
		StopChan:       stopChan,
		IncrementFlag:  false,
		AfterTimeStamp: &afterTimeStamp,
		TimeStamp:      time.Now(),
		FinalData:      &data,
		times:          &times,
		StartIndex:     &startIndex,
		EndIndex:       &endIndex,
		FinalDataIndex: 0,
		DataId:         "",
	}

	task := &WorkerTask{
		Father:     true,
		Args:       workerFuncArgs,
		FatherFunc: fatherWorkerFunc,
		SubFunc:    childWorkerFunc,
	}

	GlobalPool.Submit(task)

	err := <-stopChan
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println("最终数据：")
	for _, val := range data.Data {
		fmt.Println(val.Id, val.Ids)
		fmt.Println("============")
	}
	return
}
